﻿//#define _CRT_SECURE_NO_WARNINGS
//#include <stdio.h>
//#include <stdlib.h>
//#include <stddef.h>
#include "common.h"
// C/C++ 学习网站：https://legacy.cplusplus.com 注意旧版本（搜索）和新版本

// 匿名结构体，只能用一次，实际写程序过程中应该尽量避免使用
struct
{
    char name[30]; // 30 字节的字符数组
    wchar_t age; // 2 或 4 字节的整数，wchar_t 就是 unsigned short
    float height; // 4 字节的浮点数
    float weight; // 4 字节的浮点数
} s1, s2 = { "Jerry", 25, 1.8f, 70.5f };
// 声明匿名结构体变量，只能在这用一次，可以创建多个匿名结构体变量

struct
{
    char name[30];
    int age;
    float height;
    float weight;
} as1[20], * ap1;// 数组表示可以存放20个结构体，指针表示结构体变量指针类型

void test_struct()
{
    ap1 = &s1; // 结构体变量指针赋值，可能会有警告，成员一样，但依然不是同类型
    //s1 = {"Tom", 20, 1.75, 60.5}; // 匿名结构体变量不能像这样赋值
    s1 = s2; // 结构体变量赋值
    as1[0] = *ap1; // 数组赋值，这里只能是 ap1 指向的结构体变量，不能是 s1、s2 变量
    as1[0].age = 20; // 结构体变量的修改
    // 结构体变量的访问
    printf("Name: %s, Age: %d, Height: %.2f, Weight: %.2f\n",
        as1[0].name, as1[0].age, as1[0].height, as1[0].weight);
    printf("sizeof(s1) = %zd\n", sizeof s1); // 计算结构体变量的大小
    printf("sizeof(struct Node) = %zd\n", sizeof(struct Node));
    printf("sizeof(link) = %zd\n", sizeof(link)); // 8 字节的指针
    printf("sizeof(unsigned short) = %zd\n", sizeof(unsigned short)); // 2

    link l1 = (link)malloc(sizeof(link)); // 申请内存，并转换为结构体指针
    link l2 = (link)malloc(sizeof(link)); // 申请内存，并转换为结构体指针
    if (l1 != NULL && l2 != NULL)
    {
        l1->data = 1.23f; // 结构体指针赋值
        l1->next = l2; // 结构体指针赋值，指向下一个节点
        l2->data = 4.56f;
        l2->next = NULL;
        printf("l1->next->data = %.2f\n", l1->next->data); // 结构体指针访问
    }

    // 结构体初始化
    struct student std1 = { "Female", "Alice", 22, {85.5f, 90.5f, 82.0f} };
    // 不完全初始化，只给了前面部分成员
}

void struct_align()
{ // 结构体在内存中的对齐
    struct test1
    {
        char c1; // 1 字节，对齐到 4 字节
        int i1; // 4 字节
        char c2; // 1 字节，对齐到 4 字节
        int i2; // 4 字节
        char c3; // 1 字节
        char c4; // 1 字节
    };
    printf("sizeof(struct test1) = %zd\n", sizeof(struct test1)); // 20
    printf("test1.c1 偏移量为：%zd\n", offsetof(struct test1, c1)); // 0
    printf("test1.i1 偏移量为：%zd\n", offsetof(struct test1, i1)); // 4
    printf("test1.c2 偏移量为：%zd\n", offsetof(struct test1, c2)); // 8
    printf("test1.i2 偏移量为：%zd\n", offsetof(struct test1, i2)); // 12
    printf("test1.c3 偏移量为：%zd\n", offsetof(struct test1, c3)); // 16
    printf("test1.c4 偏移量为：%zd\n", offsetof(struct test1, c4)); // 17

    printf("sizeof(struct student) = %zd\n", sizeof(struct student));
    printf("student.name 偏移量为：%zd\n", offsetof(struct student, name));
    printf("student.age 偏移量为：%zd\n", offsetof(struct student, age));
    printf("student.score 偏移量为：%zd\n", offsetof(struct student, score));
    printf("student.gpa 偏移量为：%zd\n", offsetof(struct student, gpa));
    printf("student.address 偏移量为：%zd\n",
        offsetof(struct student, address));
    printf("student.phone 偏移量为：%zd\n", offsetof(struct student, phone));

    // 结构体默认对齐数修改
#pragma pack(push, 1) // 修改默认对齐数为 1 字节
    struct test2
    {
        char c1; // 1 字节
        int i1; // 4 字节
        double d1; // 8 字节
    };
#pragma pack(pop) // 恢复默认对齐数 8 这里 pop 可不写
    printf("sizeof(struct test2) = %zd\n", sizeof(struct test2)); // 13
}

void struct_print(struct Person p1, const struct Person* p2)
{ // 结构体作为参数，一般来说：内存中 p1 > p2，推荐使用指针
    printf("Name1: %s;\nAge1: %d;\nGender1: %s;\n\
Weight1: %.2f;\nHeight1: %.2f;\nPhone1: %s,\nAddress1: %s\n",
p1.name, p1.age, p1.detail.gender, p1.detail.weight, p1.detail.height,
p1.detail.phone, p1.detail.address);
    printf("Name2: %s;\nAge2: %d;\nGender2: %s;\n\
Weight2: %.2f;\nHeight2: %.2f;\nPhone2: %s,\nAddress2: %s\n",
p2->name, p2->age, p2->detail.gender, p2->detail.weight,
p2->detail.height, p2->detail.phone, p2->detail.address);
}

void bit_field_test()
{
    struct A a1 = { 5, 2, 5, 500, 1000, 20 }; // 位段结构体，放不下就截断
    printf("sizeof(struct A) = %zd\n", sizeof(struct A)); // 20 人工判定困难
    //printf("offsetof(struct A, _a) = %zd\n", offsetof(struct A, _a));

    printf("a1._a = %d, a1._b = %d, a1._c = %d, \
a1._d = %d，a1._e = %d, a1._f = %d\n",
a1._a, a1._b, a1._c, a1._d, a1._e, a1._f);

    // 位段结构体的使用：能够与其他类型共存
    struct B b1 = { 10, 2000, 30, 0, 1, 100, 25.6f };
    printf("sizeof(struct B) = %zd\n", sizeof(struct B)); // 24
    printf("b1._a = %d, b1._b = %d, b1._c = %d, \
b1._d = %d，b1._e = %d, b1._f = %d, b1._g = %.1f\n",
b1._a, b1.b, b1._c, b1._d, b1._e, b1._f, b1.g);
}

